Attribut: pack_mode
Das Pragma legt fest, wie eine Datenstruktur während der Allozierung gepackt wird. Das Attribut muss oberhalb der Datenstruktur eingefügt werden und wirkt sich auf das Packen der gesamten Struktur aus.
Syntax:
{attribute 'pack_mode' := ' <pack mode value> '}
Einfügeort: Oberhalb der Deklaration der Datenstruktur
<pack mode value>
| Assoziierte Packungsart | Beschreibung |
|---|---|---|
0 | aligned | Es liegen alle Variablen auf Byte-Adressen; es treten keine Speicherlücken auf. |
1 | 1-byte-aligned | |
2 | 2-byte-aligned | . Es liegen
|
4 | 4-byte-aligned | . Es liegen
|
8 | 8-byte-aligned | . Es liegen
|
Tipp
Abhängig vom Aufbau der Struktur kann es vorkommen, dass es keinen Unterschied in der Speicheraufteilung zwischen den einzelnen Modi gibt. Beispielsweise kann die Speicherverteilung einer Struktur mit dem Pragma {attribute 'pack mode' := '4'} der von {attribute 'pack mode' := '8'} entsprechen.
Tipp
Arrays von Strukturen
Werden die Strukturen in Arrays zusammengefasst, dann werden am Ende der Struktur Bytes eingefügt, damit die nächste Struktur wieder aligned ist.
Wichtig
Wenn in der Symbolkonfiguration die Option Kompatibilitätslayout aktiviert wird und gleichzeitig das Attribut 'pack_mode' im Code verwendet wird, können Probleme wegen unabsichtlich falscher Speicherausrichtung auftreten.
Beispiel 1
{attribute 'pack_mode' := '1'}
TYPE myStruct:
STRUCT
Enable: BOOL;
Counter: INT;
MaxSize: BOOL;
MaxSizeReached: BOOL;
END_STRUCT
END_TYPEDer Speicherbereich für eine Variable vom Datentyp myStruct wird „aligned“ alloziert: Ist die Speicheradresse ihrer Komponente Enable beispielsweise 0x0100, dann folgt die Komponente Counter an der Adresse 0x0101, MaxSize an Adresse 0x0103 und MaxSizeReached an Adresse 0x0104. Mit 'pack_mode':=2 läge Counter bei 0x0102, MaxSize bei 0x0104 und MaxSizeReached bei 0x0105.
Beispiel 2
STRUCT Var1 : BOOL := 16#01; Var2 : BYTE := 16#11; Var3 : WORD := 16#22; Var4 : BYTE := 16#44; Var5 : DWORD := 16#88776655; Var6 : BYTE := 16#99; Var7 : BYTE := 16#AA; Var8 : DWORD := 16#AA; END_TYPE
pack_mode = 8 | pack_mode = 0 | pack_mode = 1 | pack_mode = 2 | pack_mode = 4 | ||||||
|---|---|---|---|---|---|---|---|---|---|---|
Variable | Wert | Variable | Wert | Variable | Wert | Variable | Wert | Variable | Wert | |
0 |
|
|
|
|
|
|
|
|
|
|
1 |
|
|
|
|
|
|
|
|
|
|
2 |
|
|
|
|
|
|
|
|
|
|
3 | … |
| … |
| … |
| … |
| … |
|
4 |
|
|
|
|
|
|
|
|
|
|
5 |
|
|
|
| ||||||
6 | … |
| … |
|
|
| ||||
7 | … |
| … |
| … |
| ||||
8 |
|
| … |
| … |
| … |
|
|
|
9 | … |
|
|
|
|
| … |
| … |
|
10 | … |
|
|
|
|
|
|
| … |
|
11 | … |
|
|
|
|
|
|
| … |
|
12 |
|
| … |
| … |
|
|
|
|
|
13 |
|
| … |
| … |
| … |
|
|
|
14 | … |
| … |
| … |
| ||||
15 | … |
| ||||||||
16 |
|
|
|
| ||||||
17 | … |
| … |
| ||||||
18 | … |
| … |
| ||||||
19 | … |
| … |
| ||||||
20 | ||||||||||
21 | ||||||||||
22 | ||||||||||
23 | ||||||||||
24 | ||||||||||
25 | ||||||||||
26 | ||||||||||
27 | ||||||||||
28 | ||||||||||
29 | ||||||||||
30 | ||||||||||
31 | ||||||||||
Beispiel 3
STRUCT
Var1 : BYTE := 16#01;
Var2 : LWORD := 16#11;
Var3 : BYTE := 16#22;
Var4 : BYTE := 16#44;
Var5 : DWORD := 16#88776655;
Var6 : BYTE := 16#99;
Var7 : BYTE := 16#AA;
Var8 : WORD := 16#AA;
END_TYPEpack_mode = 8 | pack_mode = 0 | pack_mode = 1 | pack_mode = 2 | pack_mode = 4 | ||||||
|---|---|---|---|---|---|---|---|---|---|---|
Variable | Wert | Variable | Wert | Variable | Wert | Variable | Wert | Variable | Wert | |
0 |
|
|
|
|
|
|
|
|
|
|
1 |
|
|
|
| ||||||
2 | … |
| … |
|
|
| ||||
3 | … |
| … |
| … |
| ||||
4 | … |
| … |
| … |
|
|
| ||
5 | … |
| … |
| … |
| … |
| ||
6 | … |
| … |
| … |
| … |
| ||
7 | … |
| … |
| … |
| … |
| ||
8 |
|
| … |
| … |
| … |
| … |
|
9 | … |
|
|
|
|
| … |
| … |
|
10 | … |
|
|
|
|
|
|
| … |
|
11 | … |
|
|
|
|
|
|
| … |
|
12 | … |
| … |
| … |
|
|
|
|
|
13 | … |
| … |
| … |
| … |
|
|
|
14 | … |
| … |
| … |
| … |
| ||
15 | … |
|
|
|
|
| … |
| ||
16 |
|
|
|
|
|
|
|
|
|
|
17 |
|
|
|
|
|
|
|
| … |
|
18 | … |
| … |
|
|
| … |
| ||
19 | … |
| … |
| ||||||
20 |
|
|
|
| ||||||
21 | … |
|
|
| ||||||
22 | … |
|
|
| ||||||
23 | … |
| … |
| ||||||
24 |
|
| ||||||||
25 |
|
| ||||||||
26 |
|
| ||||||||
27 | … |
| ||||||||
28 | ||||||||||
29 | ||||||||||
30 | ||||||||||
31 | ||||||||||
Verhalten ohne 'pack-mode'
Wenn 'pack-mode' nicht verwendet wird, dann verwendet der Compiler typischerweise pack-mode 4 oder 8, abhängig von der Gerätebeschreibung. In jedem Fall wird ein für den Prozessor besonders vorteilhafter pack-mode verwendet, so dass Speicherzugriffe besonders effizient durchgeführt werden können. Dies wird auch natürliches Alignment genannt, oder eine natürliche Ausrichtung der Daten.
Negative Auswirkungen bei Anwendung von 'pack-mode'
Durch die Verwendung des Attributs 'pack_mode' kann es zu nicht ausgerichteten Speicherzugriffen kommen. Das bedeutet beispielsweise, dass ein Datentyp der Größe 4 Byte dann auf einer Adresse liegt, die nicht durch 4 teilbar ist. Normalerweise kann auf einem 32-Bit-System ein 32 Bit großer Datentyp mit einem einzigen Speicherzugriff gelesen und geschrieben werden. Auf manchen Plattformen, wie beispielsweise auf ARM-Plattformen, ist das jedoch nur möglich, wenn dieser Wert im Speicher ausgerichtet ist. Auf anderen Plattformen kann es sein, dass der Zugriff zwar möglich ist, aber deutlich langsamer ausgeführt wird.
{attribute 'pack_mode':=1}
TYPE DUT
STRUCT
by1 : BYTE;
dw1 : DWORD;
END_STRUCT
END_TYPEAuf einer ARM-Plattform kann der Wert dw1 nicht mit einem einzigen Zugriff gelesen werden. Bei dem Versuch auf dieses Element direkt zuzugreifen, wird der ARM-Prozessor eine Exception auslösen.
Annahme: Folgender lesender Zugriff wird durchgeführt: dwTest := dut1.dw1;
Für diesen Zugriff auf das DWORD dw1 werden 4 Speicherzugriffe benötigt, da jedes Byte einzeln eingelesen, geshiftet und verodert wird. Der Ablauf ist in etwa der Gleiche, wie wenn in dem folgenden Beispiel aus einem Array von 4 Bytes ein DWORD generiert wird:
dwHelp := bytes[0]; dwResult := dwHelp; dwHelp := bytes[1]; dwHelp := SHL(dwHelp, 8); dwResult := dwResult OR dwHelp; dwHelp := bytes[2]; dwHelp := SHL(dwHelp, 16); dwResult := dwResult OR dwHelp; dwHelp := bytes[3]; dwHelp := SHL(dwHelp, 24); dwResult := dwResult OR dwHelp;
Es ist offensichtlich, dass ein solcher Zugriff deutlich langsamer ist als ein Zugriff auf ein DWORD, das passend im Speicher ausgerichtet ist.
pdw := ADR(dut1.dw1); dwTest := pdw^;
Den Zugriff des Beispiels wird der Compiler jedoch nicht generieren, wenn über einen Pointer auf eine solche Komponente zugegriffen wird. Das bedeutet, dass der folgende Code auf einer ARM-Plattform zu einer Exception führt.
pdw := ADR(dut1.dw1); dwTest := pdw^;
Aus Performance-Gründen sollte es daher vermieden werden, mit Strukturen zu arbeiten, die nicht natürlich ausgerichtet sind.
Eine gepackte Struktur darf keine ungepackte Struktur enthalten.